// ArrayBase.js

import {
  defineComponent,
  provide,
  inject,
  toRefs,
  ref,
  onBeforeUnmount,
  h,
} from 'vue';
import { Fragment, useField, useFieldSchema, RecursionField } from '@formily/vue';
import { isValid, uid, clone } from '@formily/shared';
import { ArrayField } from '@formily/core';
import { stylePrefix } from '../__builtins__/configs';
import { Button, Icon } from 'vant';
import { composeExport } from '../__builtins__/shared';
import { CellGroup } from 'vant';

// 判断是否为 Addition 组件
const isAdditionComponent = (schema) => {
  return schema['x-component']?.indexOf('Addition') > -1;
};

// 创建 InjectionKey
const ArrayBaseSymbol = Symbol('ArrayBaseContext');
const ItemSymbol = Symbol('ItemContext');

// 使用 ArrayBase 上下文
const useArray = () => {
  return inject(ArrayBaseSymbol, null);
};

// 使用 Index
const useIndex = (index) => {
  const injected = inject(ItemSymbol);
  if (injected) {
    const { index: indexRef } = toRefs(injected);
    return indexRef;
  }
  return ref(index);
};

// 使用 Record
const useRecord = (record) => {
  const injected = inject(ItemSymbol);
  if (injected) {
    const { record: recordRef } = toRefs(injected);
    return recordRef;
  }
  return ref(record);
};

// 判断 schema 是否为对象类型
const isObjectValue = (schema) => {
  if (Array.isArray(schema?.items)) return isObjectValue(schema.items[0]);

  if (schema?.items?.type === 'array' || schema?.items?.type === 'object') {
    return true;
  }
  return false;
};

// 使用 Key
const useKey = (schema) => {
  const isObject = isObjectValue(schema);
  let keyMap = null;

  if (isObject) {
    keyMap = new WeakMap();
  } else {
    keyMap = [];
  }

  onBeforeUnmount(() => {
    keyMap = null;
  });

  return {
    keyMap,
    getKey: (record, index) => {
      if (keyMap instanceof WeakMap) {
        if (!keyMap.has(record)) {
          keyMap.set(record, uid());
        }
        return `${keyMap.get(record)}-${index}`;
      }

      if (!keyMap[index]) {
        keyMap[index] = uid();
      }

      return `${keyMap[index]}-${index}`;
    },
  };
};

// 获取默认值
const getDefaultValue = (defaultValue, schema) => {
  if (isValid(defaultValue)) return clone(defaultValue);
  if (Array.isArray(schema?.items))
    return getDefaultValue(defaultValue, schema.items[0]);
  if (schema?.items?.type === 'array') return [];
  if (schema?.items?.type === 'boolean') return true;
  if (schema?.items?.type === 'date') return '';
  if (schema?.items?.type === 'datetime') return '';
  if (schema?.items?.type === 'number') return 0;
  if (schema?.items?.type === 'object') return {};
  if (schema?.items?.type === 'string') return '';
  if (schema?.items?.type === 'void') return '';
  return null;
};

// ArrayBase 组件
const ArrayBaseInner = defineComponent({
  name: 'ArrayBase',
  props: {
    disabled: {
      type: Boolean,
      default: false,
    },
    keyMap: {
      type: [WeakMap, Array],
      default: null,
    },
  },
  setup(props, { slots }) {
    const field = useField();
    const schema = useFieldSchema();

    provide(ArrayBaseSymbol, {
      field,
      schema,
      props,
      listeners: {},
      keyMap: props.keyMap,
    });

    return () => {
      return h(Fragment, {}, slots);
    };
  },
});

// ArrayBaseItem 组件
const ArrayBaseItem = defineComponent({
  name: 'ArrayBaseItem',
  props: ['index', 'record'],
  setup(props, { slots }) {
    provide(ItemSymbol, props);
    return () => {
      return h(Fragment, {}, slots);
    };
  },
});

// ArrayBaseIndex 组件
const ArrayBaseIndex = defineComponent({
  name: 'ArrayBaseIndex',
  setup(_, { attrs }) {
    const index = useIndex();
    const prefixCls = `${stylePrefix}-array-base`;
    return () => {
      return h(
        'span',
        {
          class: `${prefixCls}-index`,
          ...attrs,
        },
        `#${index.value + 1}.`
      );
    };
  },
});

// ArrayBaseAddition 组件
const ArrayBaseAddition = defineComponent({
  name: 'ArrayBaseAddition',
  props: ['title', 'method', 'defaultValue'],
  setup(props, { listeners }) {
    const self = useField();
    const array = useArray();
    const prefixCls = `${stylePrefix}-array-base`;

    return () => {
      if (!array) return null;
      if (array.field.value.pattern !== 'editable') return null;

      return h(
        Button,
        {
          class: `${prefixCls}-addition`,
          size: 'small',
          plain: true,
          icon: 'plus',
          ...props,
          on: {
            ...listeners,
            click: (e) => {
              e?.stopPropagation?.();
              e?.preventDefault?.();
              if (array.props?.disabled) return;
              const defaultValue = getDefaultValue(
                props.defaultValue,
                array.schema.value
              );
              if (props.method === 'unshift') {
                array.field.value.unshift(defaultValue);
                array.listeners?.add?.(0);
              } else {
                array.field.value.push(defaultValue);
                array.listeners?.add?.(array.field.value.length - 1);
              }
              if (listeners.click) {
                listeners.click(e);
              }
            },
          },
        },
        self.value.title || props.title
      );
    };
  },
});

// ArrayBaseRemove 组件
const ArrayBaseRemove = defineComponent({
  name: 'ArrayBaseRemove',
  props: ['name', 'title', 'index'],
  setup(props, { attrs, listeners }) {
    const indexRef = useIndex(props.index);
    const base = useArray();
    const prefixCls = `${stylePrefix}-array-base`;

    return () => {
      if (base?.field.value.pattern !== 'editable') return null;

      return h(
        Icon,
        {
          class: `${prefixCls}-remove`,
          name: props.name || 'delete-o',
          ...attrs,
          on: {
            ...listeners,
            click: (e) => {
              e?.stopPropagation?.();
              e?.preventDefault?.();
              if (Array.isArray(base?.keyMap)) {
                base.keyMap.splice(indexRef.value, 1);
              }

              base.field.value.remove(indexRef.value);
              base.listeners?.remove?.(indexRef.value);

              if (listeners.click) {
                listeners.click(e);
              }
            },
          },
        },
        props.title
      );
    };
  },
});

// 导出 ArrayBase 组件
export const ArrayBase = composeExport(ArrayBaseInner, {
  Index: ArrayBaseIndex,
  Item: ArrayBaseItem,
  Addition: ArrayBaseAddition,
  Remove: ArrayBaseRemove,
  useArray,
  useIndex,
  useKey,
  useRecord,
});

export default ArrayBase;
